package org.irri.smta.service.impl;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Map;

import javax.inject.Named;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;

import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JasperExportManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.export.JRXlsExporter;
import net.sf.jasperreports.engine.export.JRXlsExporterParameter;
import net.sf.jasperreports.engine.util.JRLoader;

import org.irri.smta.service.IReportService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

@Named("reportService")
@Transactional(readOnly = true)
public class ReportService implements IReportService {

	private static final Logger LOGGER = LoggerFactory
			.getLogger(ReportService.class);

	@Autowired
	private DataSource dataSource;
	
	@Transactional(readOnly = true)
	@Override
	public void createExcelReport(Map<String, Object> params,
			String jasperReportFilePathname, String tempFilePathname)
			throws SQLException {
		Connection connection = null;
		try {
			connection = dataSource.getConnection();

			JasperReport jasperReport = (JasperReport) JRLoader
					.loadObject(new File(jasperReportFilePathname));
			JasperPrint jasperPrint = JasperFillManager.fillReport(
					jasperReport, params, connection);

			OutputStream outputFile = new FileOutputStream(new File(
					tempFilePathname));
			ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
			JRXlsExporter exporterXLS = new JRXlsExporter();
			exporterXLS.setParameter(JRXlsExporterParameter.JASPER_PRINT,
					jasperPrint);
			exporterXLS.setParameter(JRXlsExporterParameter.OUTPUT_STREAM,
					outputStream);
			exporterXLS
					.setParameter(JRXlsExporterParameter.IS_ONE_PAGE_PER_SHEET,
							Boolean.FALSE);
			exporterXLS.setParameter(
					JRXlsExporterParameter.IS_DETECT_CELL_TYPE, Boolean.TRUE);
			exporterXLS.setParameter(
					JRXlsExporterParameter.IS_WHITE_PAGE_BACKGROUND,
					Boolean.FALSE);
			exporterXLS.setParameter(
					JRXlsExporterParameter.IS_REMOVE_EMPTY_SPACE_BETWEEN_ROWS,
					Boolean.TRUE);
			exporterXLS
					.setParameter(
							JRXlsExporterParameter.IS_REMOVE_EMPTY_SPACE_BETWEEN_COLUMNS,
							Boolean.TRUE);
			exporterXLS.setParameter(
					JRXlsExporterParameter.IS_COLLAPSE_ROW_SPAN, Boolean.TRUE);
			exporterXLS.exportReport();
			outputFile.write(outputStream.toByteArray());
			outputFile.flush();
			outputFile.close();
		} catch (SQLException e) {
			LOGGER.error("Error in SQL! " + e.getMessage());
		} catch (JRException e) {
			LOGGER.error("Error in Jasper Reports! " + e.getMessage());
		} catch (FileNotFoundException e) {
			LOGGER.error("Report file not found! " + e.getMessage());
		} catch (IOException e) {
			LOGGER.error("Read/write exception! " + e.getMessage());
		} finally {
			connection.close();
		}
	}

	@Transactional(readOnly = true)
	@Override
	public void createPdfReport(Map<String, Object> params,
			String jasperReportFilePathname, String tempFilePathname)
			throws SQLException {
		Connection connection = null;
		try {
			connection = dataSource.getConnection();

			JasperReport jasperReport = (JasperReport) JRLoader
					.loadObject(new File(jasperReportFilePathname));
			JasperPrint jasperPrint = JasperFillManager.fillReport(
					jasperReport, params, connection);
			JasperExportManager.exportReportToPdfFile(jasperPrint,
					tempFilePathname);
		} catch (SQLException e) {
			LOGGER.error("Error in SQL! " + e.getMessage());
		} catch (JRException e) {
			LOGGER.error("Error in Jasper Reports! " + e.getMessage());
		} finally {
			connection.close();
		}
	}

	@Transactional(readOnly = true)
	@Override
	public void createPdfReportToStream(Map<String, Object> params,
			String jasperReportFilePathname, String tempFilePathname,
			OutputStream outputStream) throws SQLException {
		Connection connection = null;
		try {
			connection = dataSource.getConnection();

			JasperReport jasperReport = (JasperReport) JRLoader
					.loadObject(new File(jasperReportFilePathname));
			JasperPrint jasperPrint = JasperFillManager.fillReport(
					jasperReport, params, connection);
			JasperExportManager.exportReportToPdfStream(jasperPrint,
					outputStream);
		} catch (SQLException e) {
			LOGGER.error("Error in SQL! " + e.getMessage());
		} catch (JRException e) {
			LOGGER.error("Error in Jasper Reports! " + e.getMessage());
		} finally {
			connection.close();
		}
	}

	@Override
	public void sendFileToHttpOutputStream(String filePathname,
			HttpServletResponse response, String contentType,
			String contentDisposition) throws IOException {
		FileInputStream fis = null;
		OutputStream out = null;
		try {
			File file = new File(filePathname);
			byte[] b = new byte[(int) file.length()];
			response.setContentType(contentType);
			response.setHeader("Content-Disposition", contentDisposition);
			out = response.getOutputStream();
			fis = new FileInputStream(file);
			fis.read(b);
			out.write(b);
			out.flush();
		} finally {
			if (fis != null) {
				fis.close();
			}
			if (out != null) {
				out.close();
			}
		}
	}

}
